#pragma once
#include <mutex>
#include <sys/eventfd.h>
#include <thread>
#include <condition_variable>
#include "Poller.hpp"
#include "Timewheel.hpp"
class TimerWheel;
using Functor = std::function<void()>;
//EventLoop模块就是Reactor模块，它是对Poller模块，TimerQueue模块，Socket模块的⼀个整体封装，进行所有描述符的事件监控。 
class EventLoop
{
public:
    EventLoop()
        :_threadId(std::this_thread::get_id())
        ,_eventFd(CreateEventFd())
        ,_eventChannel(std::make_unique<Channel>(this, _eventFd))
        ,_timerwheel(this)
    {
        _eventChannel->SetReadCallback(std::bind(&EventLoop::ReadEventFd, this));//给_eventFd添加可读事件回调函数，读取_eventFd事件通知次数
        _eventChannel->EnableRead();//启动读事件监控    
    }
public:
    //启动EventLoop模块,1、事件监控2、就绪事件处理3、执行任务
    void StartEventLoop()
    {
        while(1)
        {
            //事件监控
            std::vector<Channel*> actives;
            _poller.Poll(&actives);//开始监控，返回活跃的channel连接数组
            //就绪事件处理
            for (auto& channel : actives)
            {
                channel->HandleEvent();//事件处理，一旦连接触发了事件，就调用这个函数，自己触发什么事件如何处理由自己决定
            } 
            //执行任务
            RunAllTask();//将任务池中的任务取出并执行
        }
    }
    //用于判断当前线程是否是EventLoop对应的线程
    bool IsInLoop() const { return _threadId == std::this_thread::get_id(); }
    //断言某个操作必须在线程中，用于判断当前线程是否是EventLoop对应的线程
    void AssertInLoop()
    {
        assert(IsInLoop());
    }
    //判断将要执行的任务是否处于当前线程中，如果是则执行，不是则压入任务队列 
    void RunInLoop(const Functor& callback)
    {
        if(IsInLoop()) { callback(); }
        else { return QueueInLoop(callback); }
    }
    //将操作压入任务队列
    void QueueInLoop(const Functor& callback)
    {
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _tasks.push_back(callback);
        }
        //去唤醒有可能因为没有事件就绪而导致的 epoll阻塞
        //其实就是给eventfd写入一个数据，eventfd就会触发可读事件，就不会再阻塞了
        WeakUpEventFd();
    }
    //添加、修改描述符的监控事件
    void UpdateEvent(Channel* channel) { _poller.UpdateEvent(channel); }
    //移除描述符的监控事件
    void RemoveEvent(Channel* channel) { _poller.RemoveEvent(channel); }
    //添加定时器任务
    void TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc& callback) { _timerwheel.TimerAdd(id, timeout, callback); }
    //刷新定时任务
    void TimerRefresh(uint64_t id) { _timerwheel.TimerRefresh(id); }
    //取消定时器任务
    void TimerCancel(uint64_t id) { _timerwheel.TimerCancel(id); }
    //检测是否存在某个定时器任务
    bool HasTimer(uint64_t id) { return _timerwheel.HasTimer(id); }
private:
    //将任务池中的任务取出并执行
    void RunAllTask() 
    {
        std::vector<Functor> functor;
        {
            std::unique_lock<std::mutex> lock(_mtx);//自动锁定和解锁互斥锁的功能
            _tasks.swap(functor);//将任务移交给functor，_tasks被清空
        }
        for (auto& f : functor)//取出functor中的任务，逐个执行
        {
            f(); 
        }
    }
    //创建eventfd
    static int CreateEventFd()
    {
        int efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
        if (efd < 0)
        {
            ERROR_LOG("CREATE EVENTFD FAILED!!");
            abort();//让程序异常退出
        }
        return efd;
    }
    //读取eventfd的事件通知次数
    void ReadEventFd()
    {
        uint64_t res = 0;
        int ret = read(_eventFd, &res, sizeof(res));//_eventFd中的计数不为0就会一直触发事件
        if (ret < 0)
        {
            //EINTR:被信号打断 EAGAIN:无数据可读
            if (errno == EINTR || errno == EAGAIN) { return; }
            ERROR_LOG("READ EVENTFD FAILED!");
            abort();
        }
    }
    //唤醒有可能因为没有事件就绪而导致的epoll阻塞（对_eventFd写入一个数据）
    void WeakUpEventFd()
    {
        uint64_t val = 1;
        int ret = write(_eventFd, &val, sizeof(val));
        if (ret < 0)
        {
            //EINTR:被信号打断 EAGAIN:无数据可读
            if (errno == EINTR || errno == EAGAIN) { return; }
            ERROR_LOG("WRITE EVENTFD FAILED!");
            abort();
        }
    }
private:
    std::thread::id _threadId;//线程ID，如果执行的操作的线程id和该变量一致，无需压入任务队列直接执行。反之需要加入任务队列，等事件处理完了再执行
    int _eventFd;//防止eventfd唤醒事件监控有可能导致的阻塞
    std::unique_ptr<Channel> _eventChannel;//通过_eventChannel管理_eventFd
    Poller _poller;//Poller对象
    std::vector<Functor> _tasks;//任务队列，将Channel中监听到的事件存入vector
    std::mutex _mtx;//保证任务队列的线程安全
    TimerWheel _timerwheel;//定时器模块
}; 
//将EventLoop和thread整合到一起
class LoopThread
{
public:
    //创建线程，设定线程入口函数
    LoopThread()
        :_loop(nullptr)
        ,_thread(std::thread(&LoopThread::ThreadEntry, this))
    {}
    //返回当前线程关联的EventLoop对象的指针
    EventLoop* GetLoop()
    {  
        EventLoop* loop = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _cond.wait(lock, [&](){ return _loop != nullptr; });//loop为空就持续阻塞，等待ThreadEntry函数唤醒
            loop = _loop;
        }
        return loop;
    }
private:
    //实例化EventLoop对象，唤醒_cond上阻塞的线程，并且开始运行EventLoop模块的功能
    void ThreadEntry()
    {
        EventLoop loop;//实例化EventLoop对象
        {
            std::unique_lock<std::mutex> lock(_mtx);//加锁
            _loop = &loop;
            _cond.notify_all();//唤醒_cond上阻塞的线程
        }
        loop.StartEventLoop();//循环执行就绪任务,运行EventLoop模块的功能
    }
private:
    EventLoop* _loop;//EventLoop的指针，这个对象需要在线程内部进行实例化 
    std::thread _thread;//EventLoop对应的线程
    //避免线程创建但_loop并没有被实例化（此时调用GetLoop接口将会返回空）
    std::mutex _mtx;//互斥锁
    std::condition_variable _cond;//条件变量
};

//针对LoopThread将EventLoop和thread整合到一起
class LoopThreadPool
{
public:
    LoopThreadPool(EventLoop* baseLoop)
        :_threadCount(0)
        ,_nextIdx(0)
        ,_baseLoop(baseLoop)
    {}
public:
    //设置线程数量
    void SetThreadCount(int count) { _threadCount = count; }
    //创建所有从属线程
    void Create()
    {
        if (_threadCount > 0)
        {
            _threads.resize(_threadCount);
            _loops.resize(_threadCount);
            for (int i = 0; i < _threadCount; ++i)
            {
                _threads[i] = new LoopThread();
                _loops[i] = _threads[i]->GetLoop();//返回当前线程关联的EventLoop对象的指针
            }
        }
    }
    //分配下一个Loop
    EventLoop* NextLoop()
    {
        if (_threadCount == 0)//如果从属线程为0，所有操作都将由主线程执行
        {
            return _baseLoop;//一直是主线程执行
        }
        _nextIdx = (_nextIdx + 1) % _threadCount;//RR轮转
        return _loops[_nextIdx];
    }
private:
    int _threadCount;//所需创建的从属线程数量
    int _nextIdx;//下一个Loop的索引(用于RR轮转)
    EventLoop* _baseLoop;//主EventLoop（如果从属线程为0，所有操作都将由主线程执行）
    std::vector<LoopThread*> _threads;//保存所有LoopThread*对象
    std::vector<EventLoop*> _loops;//从属线程数量大于0则从_loops中进行EventLoop分配
};

//移除监控（从epoll红黑树中进行移除）
void Channel::Remove() { _loop->RemoveEvent(this); }
//添加或修改监控
void Channel::Update() { _loop->UpdateEvent(this); }


//向时间轮添加定时任务(销毁任务),定时器中有个timerfd，定时器信息的操作在多线程中操作存在线程安全问题
//不想加锁就把定时器的所有操作，都放到一个线程中进行
void TimerWheel::TimerAdd(uint64_t id, uint32_t timeout, const TaskFunc& taskCallBack)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerAddInLoop, this, id, timeout, taskCallBack));
}
//在时间轮中刷新定时任务（在unordered_map找到弱指针，通过弱指针构造共享指针）
void TimerWheel::TimerRefresh(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerRefreshInLoop, this, id));
}
//取消定时任务
void TimerWheel::TimerCancel(uint64_t id)
{
    _loop->RunInLoop(std::bind(&TimerWheel::TimerCancelInLoop, this, id));
}
